package elw.dp.app;
import com.google.common.io.ByteStreams;
import com.google.common.io.CharStreams;
import elw.dp.mips.TaskBean;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonToken;
import javax.net.ssl.HttpsURLConnection;
import javax.swing.*;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.*;
class RunnableLoadTask implements Runnable {
public static interface Callback {
void setTask(TaskBean task);
void updateStatus(String newStatus, Throwable fault);
void onTaskLoadComplete();
}
private final Callback callback;
private final ControllerSetup setup;
public RunnableLoadTask(Callback callback, ControllerSetup setup) {
this.callback = callback;
this.setup = setup;
}
private String loadFile(final String slot, final String scope, final String id) {
callback.updateStatus(
"downloading: '" + slot + "' '" + id + "'@'" + scope + "'", null
);
final String strDl =
setup.getBaseUrl() + "dl/mipsApplet.txt?elw_ctx=" + setup.getElwCtx() +
"&sId=" + slot + "&s=" + scope + "&fId=" + id;
final URL urlDl;
try {
urlDl = new URL(strDl);
} catch (MalformedURLException e) {
callback.updateStatus("download failed: '" + strDl + "'", e);
return null;
}
InputStream is = null;
try {
URLConnection ucDl = setupGet(urlDl);
is = ucDl.getInputStream();
return CharStreams.toString(
new InputStreamReader(is, "UTF-8")
);
} catch (IOException e) {
callback.updateStatus("download failed: '" + strDl + "'", e);
return null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// ignored
}
}
}
}
private URLConnection setupGet(URL url) throws IOException {
URLConnection uc = url.openConnection();
uc.setRequestProperty("Cookie", setup.getUploadHeader());
uc.setAllowUserInteraction(false);
uc.setUseCaches(false);
if (uc instanceof HttpURLConnection) {
((HttpURLConnection) uc).setInstanceFollowRedirects(false);
}
if (uc instanceof HttpsURLConnection) {
((HttpsURLConnection) uc).setInstanceFollowRedirects(false);
}
return uc;
}
public void run() {
callback.updateStatus(
"listing files from '" + setup.getBaseUrl() + "'", null
);
final String strList = setup.getBaseUrl() + "list?elw_ctx=" + setup.getElwCtx();
final URL urlList;
try {
urlList = new URL(strList);
} catch (MalformedURLException e) {
callback.updateStatus("list failed: '" + strList + "'", e);
return;
}
final ResponseList respList;
InputStream is = null;
try {
URLConnection ucList = setupGet(urlList);
is = ucList.getInputStream();
respList = readRespList(is);
} catch (IOException e) {
callback.updateStatus("list failed: '" + strList + "'", e);
return;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// ignored
}
}
}
final Map<String, String[]> slotStatement = respList.getData().get("statement");
if (slotStatement == null) {
callback.updateStatus("statement file listing not found", null);
return;
}
final String[] fileIdsStatement = slotStatement.get("v");
if (fileIdsStatement == null || fileIdsStatement.length == 0) {
callback.updateStatus("statement file listing broken", null);
return;
}
final String fileIdStatement = fileIdsStatement[fileIdsStatement.length - 1];
final String statement = loadFile("statement", "v", fileIdStatement);
if (statement == null) {
return;
}
final Map<String, String[]> slotCode = respList.getData().get("code");
if (slotCode == null) {
callback.updateStatus("code file listing not found", null);
return;
}
final String[] fileIdsCode = slotCode.get("s");
if (fileIdsCode == null) {
callback.updateStatus("code file listing broken", null);
return;
}
final String solution;
if (fileIdsCode.length > 0) {
final String fileIdCode = fileIdsCode[fileIdsCode.length - 1];
solution = loadFile("code", "s", fileIdCode);
if (solution == null) {
return;
}
} else {
solution = comment(statement, 40);
}
final Map<String, String[]> slotTest = respList.getData().get("test");
if (slotTest == null) {
callback.updateStatus("test file listing not found", null);
return;
}
final String[] fileIdsTest = slotTest.get("v");
if (fileIdsTest == null || fileIdsTest.length == 0) {
callback.updateStatus("test file listing broken", null);
return;
}
final List<String> tests = new ArrayList<String>();
for (String fileIdTest : fileIdsTest) {
final String test = loadFile("test", "v", fileIdTest);
if (test == null) {
return;
}
tests.add(test);
}
callback.updateStatus("load sequence complete", null);
callback.setTask(new TaskBean(
statement, tests, solution
));
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
callback.onTaskLoadComplete();
}
}
);
}
protected static ResponseList readRespList(InputStream is) throws IOException {
JsonFactory jf = new JsonFactory();
JsonParser jp = jf.createJsonParser(is);
ResponseList response = new ResponseList();
if (jp.nextToken() != JsonToken.START_OBJECT) {
throw new IllegalStateException("expecting start object");
}
while (jp.nextToken() != JsonToken.END_OBJECT) {
String fieldname = jp.getCurrentName();
jp.nextToken(); // move to START_OBJECT
if ("success".equals(fieldname)) {
response.setSuccess(Boolean.parseBoolean(jp.getText()));
}
if ("message".equals(fieldname)) {
response.setMessage(jp.getText()); // LATER this returns 'null' on me!
}
if ("data".equals(fieldname)) {
final Map<String, Map<String, String[]>> dataMap = new TreeMap<String, Map<String, String[]>>();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String dataKeySlot = jp.getCurrentName();
jp.nextToken(); // move to START_OBJECT
final Map<String, String[]> scopeToIdList = new TreeMap<String, String[]>();
while (jp.nextToken() != JsonToken.END_OBJECT) {
String dataKeyScope = jp.getCurrentName();
jp.nextToken(); // move to START_ARRAY
List<String> idList = new ArrayList<String>();
while (jp.nextToken() != JsonToken.END_ARRAY) {
idList.add(jp.getText());
}
scopeToIdList.put(dataKeyScope, idList.toArray(new String[idList.size()]));
}
dataMap.put(dataKeySlot, scopeToIdList);
}
response.setData(dataMap);
}
}
return response;
}
private static String comment(String statement, final int lineWidth) {
final StringBuilder st = new StringBuilder(statement.replaceAll("\\s+", " ").trim());
int pos = 0;
while (pos + 1 < st.length()) {
final String header = pos > 0 ? "\n# " : "# ";
st.insert(pos, header);
pos += header.length();
int lineLen = 0;
while (lineLen < lineWidth && pos + lineLen + 1 < st.length()) {
int nextSpace = st.indexOf(" ", pos + lineLen);
int nextPos = nextSpace >= 0 ? nextSpace + 1 : st.length() - 1;
if (lineLen != 0 && nextPos - pos > lineWidth) {
break;
}
lineLen = nextPos - pos;
}
pos += lineLen;
}
return st.toString();
}
protected void setupGet(URLConnection ucList) {
ucList.setRequestProperty("Cookie", setup.getUploadHeader());
ucList.setAllowUserInteraction(false);
ucList.setUseCaches(false);
if (ucList instanceof HttpURLConnection) {
((HttpURLConnection) ucList).setInstanceFollowRedirects(false);
}
if (ucList instanceof HttpsURLConnection) {
((HttpsURLConnection) ucList).setInstanceFollowRedirects(false);
}
}
}
class ResponseList {
protected String message;
protected boolean success;
protected Map<String, Map<String, String[]>> data = new HashMap<String, Map<String, String[]>>();
public ResponseList() {
}
public Map<String, Map<String, String[]>> getData() {
return data;
}
public void setData(Map<String, Map<String, String[]>> data) {
this.data = data;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
}